/*LICENSE_BEGIN
 * ******************************************************************
 * Copyright 2006 by the Dainamite Robocup-Team at the
 * DAI-Labor, TU-Berlin (www.dai-labor.de)
 * 
 * Members of Dainamite are:
 * Holger Endert
 * Robert Wetzker
 * Thomas Karbe
 * Axel Heßler
 * Philippe Bütter
 * Felix Brossmann
 * 
 * Licensed under the GNU GPL (General Public License) Free Software 
 * License, Version 2. You may use this file only in compliance with 
 * the License. You may obtain a copy of the License at:
 * 
 * http://www.fsf.org/licensing/licenses/gpl.txt
 * ******************************************************************
LICENSE_END*/
package robocup.component;

import java.io.IOException;
import java.io.StringReader;
import java.util.Properties;

import robocup.component.actions.InitAction;
import robocup.component.coach.CoachFactBase;
import robocup.component.coach.CoachWorld;
import robocup.component.infotypes.AuralInfo;
import robocup.component.infotypes.CoachVisualInfo;
import robocup.component.infotypes.Info;
import robocup.component.infotypes.ServerParamInfo;
import robocup.parser9.CoachParser;
import robocup.parser9.ParseException;

/**
 * The trainer (sometimes also reffered to as 'offline-coach') is an agent, 
 * which is able to change the state of the game, such that certain situations
 * can be executed repetitive, e.g. for better testing, applying learning or 
 * creating statistics. The TrainerAgent is not started directly, but 
 * instantiated via the GUI or via commandline within <code>
 * soccerscope.model.SceneSetMaker</code>. Within the robocup-package, the 
 * trainer-agent only serves as an interface to the server. The evaluation
 * and execution of training-scenarios is done in <it>SoccerScope</it>.
 */
public class TrainerAgent extends AbstractAgent {

	/**
	 * The trainers world model. Note that it also uses the same class as
	 * the online-coach.
	 */
	private CoachWorld coachWorld;

	/**
	 * Constructor of the trainer-agent simply forwards the properties of the
	 * config-file.
	 * 
	 * @param props -
	 *            the agent properties
	 */
	public TrainerAgent(Properties props) {
		super(props);
	}

	/**
	 * No extra configuration parsed.
	 */
	@Override
	protected void initConfig() {
	}

	/**
	 * Creates new instances of the <code>coachWorld</code> and of the
	 * <code>CoachParser</code>. Note, that the <code>coachWorld</code>
	 * is not used in the moment.
	 */
	@Override
	protected void initComponents() {
		this.coachWorld = new CoachWorld(new CoachFactBase());
		this.coachWorld.setAgent(this);
		this.parser = new CoachParser(new StringReader(""), this);
	}
	
	
	/**
	 * Instantiates a connection as trainer to the server. Sets eye and
	 * ear on, such that continuously messages are received. This is important,
	 * because otherwise the trainers receive-connection might produce a 
	 * timeout, which causes the agent to terminate.
	 */
	@Override
	protected boolean initProtocol() {
		try {
			// first connect
			String init = new InitAction(TRAINER, this.teamName).toString();
			this.connection.send(init);

			Info info = null;
			String rcv = null;

			rcv = this.connection.receive();
			if (rcv == null) {
				System.out.println("Error: Server does not respond in time!");
				return false;
			}

			// send eye and ear on:
			this.connection.send("(eye on)");
			this.connection.receive();
			this.connection.send("(ear on)");
			this.connection.receive();

			info = this.parser.parseCommand(rcv);

			System.out.println("[TrainerAgent] Trainer "
					+ " successfully connected! ");

			// trigger updates
			informWorld(info);
			// informTactic(info);
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		} catch (ParseException p) {
			p.printStackTrace();
			return false;
		}
		return true;
	}

	/**
	 * Simply forwards the info to the coach-world.
	 */
	@Override
	protected void processInfo(Info info) {
		informWorld(info);
	}

	/**
	 * This method delegates the updates of the worldmodel with given info, e.g.
	 * the coachVI or the aural-info were sent to different update-methods
	 * of the world-model.
	 * 
	 * @param info -
	 *            a generic info
	 */
	private void informWorld(Info info) {
		if (info == null)
			return;
		if (info.getInfoType() == Info.TYPE_COACHVI)
			this.coachWorld.update((CoachVisualInfo) info);
		else if (info.getInfoType() == Info.TYPE_AURAL)
			this.coachWorld.update((AuralInfo) info);
		else if (info.getInfoType() == Info.TYPE_SPARAM)
			this.coachWorld.setSConf(((ServerParamInfo) info).getSConf());
	}

}
